package com.unlcn.ils.wms.backend.service.outbound.impl;

import cn.huiyunche.commons.exception.BusinessException;
import cn.huiyunche.commons.utils.HttpRequestUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.unlcn.ils.wms.backend.constant.WmsConstant;
import com.unlcn.ils.wms.backend.enums.*;
import com.unlcn.ils.wms.backend.service.outbound.WmsCQOutboundService;
import com.unlcn.ils.wms.base.dto.WmsAddTMSOutboundInterfaceDTO;
import com.unlcn.ils.wms.base.dto.WmsCqInboundTmsDTO;
import com.unlcn.ils.wms.base.mapper.additional.wmsOutbound.WmsOutboundTaskExtMapper;
import com.unlcn.ils.wms.base.mapper.extmapper.WmsDepartureRegisterExtMapper;
import com.unlcn.ils.wms.base.mapper.inbound.WmsCqinboundTmsLogMapper;
import com.unlcn.ils.wms.base.mapper.inbound.WmsCqinboundTmsMapper;
import com.unlcn.ils.wms.base.mapper.inbound.WmsTmsLogMapper;
import com.unlcn.ils.wms.base.mapper.junmadcs.WmsHandoverOrderExcpMapper;
import com.unlcn.ils.wms.base.mapper.junmadcs.WmsHandoverOrderMapper;
import com.unlcn.ils.wms.base.mapper.outbound.WmsDepartureRegisterMapper;
import com.unlcn.ils.wms.base.model.inbound.WmsCqinboundTms;
import com.unlcn.ils.wms.base.model.inbound.WmsCqinboundTmsExample;
import com.unlcn.ils.wms.base.model.inbound.WmsCqinboundTmsLog;
import com.unlcn.ils.wms.base.model.inbound.WmsTmsLogWithBLOBs;
import com.unlcn.ils.wms.base.model.junmadcs.WmsHandoverOrder;
import com.unlcn.ils.wms.base.model.junmadcs.WmsHandoverOrderExcp;
import com.unlcn.ils.wms.base.model.junmadcs.WmsHandoverOrderExcpExample;
import com.unlcn.ils.wms.base.model.outbound.WmsDepartureRegister;
import com.unlcn.ils.wms.base.model.outbound.WmsOutboundTask;
import com.unlcn.ils.wms.base.model.sys.SysUser;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


@Service
public class WmsCQOutboundServiceImpl implements WmsCQOutboundService {
    private Logger logger = LoggerFactory.getLogger(WmsCQOutboundServiceImpl.class);

    @Value("${tms.pickup.host.url}")
    private String propertyUrl;
    @Value("${tms.pickup.host.timeoutfortracking}")
    private String propertyTime;
    @Value("${tms.encode.key}")
    private String propertyKey;
    @Value("${wms.tms.outbound.jm}")
    private String tmsOutboundJM;

    private final static int TOTAL_COUNT = 5;


    @Autowired
    private WmsCqinboundTmsMapper wmsCqinboundTmsMapper;
    @Autowired
    private WmsCqinboundTmsLogMapper wmsCqinboundTmsLogMapper;
    @Autowired
    private WmsDepartureRegisterMapper wmsDepartureRegisterMapper;
    @Autowired
    private WmsOutboundTaskExtMapper wmsOutboundTaskExtMapper;
    @Autowired
    private WmsDepartureRegisterExtMapper wmsDepartureRegisterExtMapper;
    @Autowired
    private WmsHandoverOrderMapper handoverOrderMapper;
    @Autowired
    private WmsHandoverOrderExcpMapper handoverOrderExcpMapper;
    @Autowired
    private WmsTmsLogMapper wmsTmsLogMapper;


    //调用tms接口查询入库指令,对接道闸接口及业务--自动调用tms
    @Override
    public HashMap<String, Object> saveOutboundDetailByVehicleFromTms(String warehouse, String vehicle, String shipno) {
        logger.info("WmsCQOutboundServiceImpl.saveOutboundDetailByVehicleFromTms param :{},{},{},{}", warehouse, vehicle, shipno);
        if (StringUtils.isBlank(vehicle)) {
            throw new BusinessException("传入的车牌号为空!");
        }
        HashMap<String, Object> resultMap = Maps.newHashMap();
        //因为先在本地查询了对应车牌的备料信息,到此方法已经是不存在数据于备料明细中.需要从tms接口调用数据
        //不能直接查询接口表中的数据,因为不知道指令号。一个板车可能进出场多次绑定了不同的指令需要区别对待
        String result = null;
        try {
            //调用Tms接口查入库指令
            result = callTms(warehouse, vehicle, shipno);
        } catch (Exception e) {
            logger.error("WmsCQOutboundServiceImpl.saveOutboundDetailByVehicleFromTms error :", e);
            resultMap.put("success", "false");
            resultMap.put("message", "调用tms接口超时失败!");
            result = "{\n" +
                    "    \"success\": false,\n" +
                    "    \"records\": null,\n" +
                    "    \"message\": \"调用tms接口超时失败!\"\n" +
                    "}";
            insertFailedData(vehicle, result, shipno);
        }
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            String msg = jsonObject.getString("message");
            String records = jsonObject.getString("records");
            Boolean success = jsonObject.getBoolean("success");
            resultMap.put("success", String.valueOf(success));
            resultMap.put("message", "闸门开启");
            if (!success) {
                logger.error("WmsCQOutboundServiceImpl.saveOutboundDetailByVehicleFromTms error msg: {}", msg);
                //不抛出异常用于 闸门口异常信息显示
                resultMap.put("message", msg);
                insertFailedData(vehicle, result, shipno);
            } else {
                //出库tms接口没有返回records
                insertWmsCqInboundTms(null, WmsSysSourceEnum.TMS.getValue(), shipno);
                insertTmsLogAndTime(vehicle, result);
                WmsDepartureRegister departureRegister = insertWmsDepartureRegister(vehicle, shipno);
                departureRegister.setDrDepartureTime(new Date());//闸门开启时间
                departureRegister.setDrDepartureType(WmsDepartureTypeEnum.TMS_SUCCESS.getValue());
                departureRegister.setDrOpenStatus(WmsDepartureOpenStatusEnum.OPENED.getValue());
                departureRegister.setWhCode(WhCodeEnum.UNLCN_XN_CQ.getValue());
                wmsDepartureRegisterMapper.insertSelective(departureRegister);
                //更新出库任务的状态为已开闸
                HashMap<String, Object> paramMap = Maps.newHashMap();
                paramMap.put("notDel", DeleteFlagEnum.NORMAL.getValue());
                paramMap.put("outFlag", WmsOutboundTaskOutboundFlagEnum.HAS_OUTBOUND.getValue());
                paramMap.put("shipNo", shipno);
                paramMap.put("vehicle", "%" + vehicle);
                paramMap.put("whCode", WhCodeEnum.UNLCN_XN_CQ.getValue());
                paramMap.put("otStatus", WmsOutboundTaskStatusEnum.WMS_OUTBOUND_TASK_STATUS_FINISHED.getValue());
                paramMap.put("quitFlag", TaskQuitFlagEnum.NOT_QUIT.getValue());
                List<WmsOutboundTask> list = wmsOutboundTaskExtMapper.selectHasGateOutList(paramMap);
                if (CollectionUtils.isNotEmpty(list)) {
                    //更新任务为已开闸状态
                    wmsOutboundTaskExtMapper.updateBatch(list);
                }
            }
        }
        return resultMap;
    }


    /**
     * 用于进行出场手动开闸门的记录--手动
     *
     * @param dto               板车车牌号
     * @param sysUser           用户id
     * @param whCode            仓库code
     * @param departureRegister 闸门记录
     */
    @Override
    public void addOutboundOpenByHm(WmsCqInboundTmsDTO dto, SysUser sysUser, String whCode, WmsDepartureRegister departureRegister) {
        logger.info("WmsCQOutboundServiceImpl.addOutboundOpenByHm param:{},{},{}", dto, sysUser, whCode);
        if (Objects.equals(dto, null))
            throw new BusinessException("参数不能为空!");
        if (StringUtils.isBlank(dto.getDrId()))
            throw new BusinessException("记录id不能为空!");
        if (StringUtils.isBlank(whCode))
            throw new BusinessException("仓库code不能为空!");
        if (!WhCodeEnum.UNLCN_XN_CQ.getValue().equals(whCode))
            throw new BusinessException("该仓库不支持此操作!");
        //后台继续调用tms接口表
        String dispatchNo = departureRegister.getDispatchNo();
        List<WmsCqinboundTms> wmsCqinboundTms = getLastWmsCqOutboundTms(departureRegister.getDrVehiclePlate());
        if (CollectionUtils.isNotEmpty(wmsCqinboundTms)) {
            WmsCqinboundTms tms = wmsCqinboundTms.get(0);
            if (String.valueOf(Boolean.FALSE).equalsIgnoreCase(tms.getTmsResult()) && tms.getTmsInnvocationCount() <= CALL_TMS_COUNT) {
                tms.setWmsOutTime(new Date());
                tms.setGmtUpdate(new Date());
                tms.setModifyUserName(sysUser.getName());
                wmsCqinboundTmsMapper.updateByPrimaryKeySelective(tms);
                if (StringUtils.isNotBlank(dispatchNo)) {
                    //再将数据传至TMS
                    ExecutorService service = null;
                    try {
                        service = Executors.newSingleThreadExecutor();
                        service.execute(() -> {
                            String result = null;
                            try {
                                result = callTms(WhCodeEnum.UNLCN_XN_CQ.getText(), departureRegister.getDrVehiclePlate(), dispatchNo);
                            } catch (Exception e) {
                                //再定时的调用tms  也可以使用延迟线程池定时执行
                                updateScheduleCallTms(departureRegister.getDrVehiclePlate(), sysUser, dispatchNo);
                            }
                            if (StringUtils.isNotBlank(result)) {
                                JSONObject jsonObject = JSONObject.parseObject(result);
                                String msg = jsonObject.getString("message");
                                Boolean success = jsonObject.getBoolean("success");
                                if (success) {
                                    //更新数据为成功
                                    insertWmsCqInboundTms(sysUser.getName(), WmsSysSourceEnum.WMS_CREATE.getValue(), dispatchNo);
                                    //保存对应的日志表
                                    insertTmsLogAndTime(departureRegister.getDrVehiclePlate(), result);
                                } else {
                                    logger.error("WmsCQOutboundServiceImpl.addOutboundOpenByHm error", msg);
                                    //再调用tms
                                    updateScheduleCallTms(departureRegister.getDrVehiclePlate(), sysUser, dispatchNo);
                                }
                            }
                        });
                        service.shutdown();
                    } catch (Exception e) {
                        logger.error("WmsCQOutboundServiceImpl.addOutboundOpenByHm 手动调用接口失败 error:", e);
                    } finally {
                        if (service != null) {
                            service.shutdown();
                        }
                    }
                }
            }
        }

    }

    /**
     * <p>
     * 2018-6-6 增加对接tms接口
     * </p>
     */
    @Override
    public void updateSendOutboundDataToTMS() {
        if (logger.isInfoEnabled()) {
            logger.info("WmsCQOutboundServiceImpl.updateSendOutboundDataToTMS start---->");
        }
        HashMap<Object, Object> params = Maps.newHashMap();
        params.put("hasPreparation", WmsPreparationPlanEnum.WMS_PLAN_FINISH.getValue());
        params.put("notSend", SendStatusEnum.SEND_INIT.getValue());
        params.put("zlCarrier", "中联物流");
        params.put("start", 0);
        params.put("end", 1);
        params.put("orderBy", "a.data_id desc");
        List<WmsAddTMSOutboundInterfaceDTO> list = wmsOutboundTaskExtMapper.selectSendOutboundDataForTmsByParams(params);
        sendTms(list);
    }

    /**
     * 发送异常的数据  到tms
     */
    @Override
    public void sendOutboundDataExcpToTMSForJM() {
        if (logger.isInfoEnabled()) {
            logger.info("WmsCQOutboundServiceImpl.updateSendOutboundDataToTMS start---->");
        }
        HashMap<Object, Object> params = Maps.newHashMap();
        params.put("sendFail", SendStatusEnum.SEND_FAILED.getValue());
        params.put("zlCarrier", "中联物流");
        params.put("start", 0);
        params.put("end", 1);
        params.put("orderBy", "a.data_id desc");
        List<WmsAddTMSOutboundInterfaceDTO> list = wmsOutboundTaskExtMapper.selectSendOutboundExcpDataForTmsByParams(params);
        sendTms(list);
    }

    private void sendTms(List<WmsAddTMSOutboundInterfaceDTO> list) {
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(v -> {
                String whCode = v.getWhCode();
                if (WhCodeEnum.JM_CS.getValue().equals(whCode)) {
                    v.setCustomId(WmsConstant.CS_CUSTOMER_ID);//客户id
                    v.setCustomName(WmsConstant.CS_CUSTOMER_NAME);
                    v.setDepartProvinceCode(WmsConstant.HN_PROVINCE_CODE);
                    v.setDepartProvinceName(WmsConstant.HN_PROVINCE_NAME);
                    v.setDepartCityCode(WmsConstant.CS_CITY_CODE);
                    v.setDepartCityName(WmsConstant.CS_CITY_NAME);
                    v.setDepartCountyCode(null);
                    v.setDepartCountyName(null);
                    v.setDepartAddr(WmsConstant.CS_ADDR);
                    v.setDepartPhone("1");
                    v.setCreator(WmsConstant.CREATOR_CS);
                }
                if (WhCodeEnum.JM_XY.getValue().equals(whCode)) {
                    v.setCustomId(WmsConstant.XY_CUSTOMER_ID);//客户id
                    v.setCustomName(WmsConstant.XY_CUSTOMER_NAME);
                    v.setDepartProvinceCode(WmsConstant.HB_PROVINCE_CODE);
                    v.setDepartProvinceName(WmsConstant.HB_PROVINCE_NAME);
                    v.setDepartCityCode(WmsConstant.XY_CITY_CODE);
                    v.setDepartCityName(WmsConstant.XY_CITY_NAME);
                    v.setDepartCountyCode(null);
                    v.setDepartCountyName(null);
                    v.setDepartAddr(WmsConstant.XY_ADDR);
                    v.setDepartPhone("1");
                    v.setCreator(WmsConstant.CREATOR_XY);
                }
                int index = v.getModelName().indexOf(";");
                if (index != -1) {
                    v.setModelDesc(v.getModelName().substring(index + 1)
                            + ";"
                            + v.getModelDesc());
                    v.setModelName(v.getModelName().substring(0, index));
                } else {
                    v.setModelDesc(v.getModelName()
                            + ";"
                            + v.getModelDesc());
                }
                v.setBurgent(WmsConstant.NOT_BURGENT);//是否加急
                v.setDistance(null);
                v.setDtshipdate(null);  //要求发运日期
                v.setDtarriveDate(null);//要求到达日期
            });
            //发送json数据到tms
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            HttpPost post = new HttpPost(tmsOutboundJM);
            RequestConfig config = RequestConfig.custom()
                    .setConnectTimeout(Integer.valueOf(propertyTime))
                    .setSocketTimeout(Integer.valueOf(propertyTime))
                    .build();
            post.setConfig(config);
            try {
                WmsAddTMSOutboundInterfaceDTO interfaceDTO = list.get(0);
                StringEntity entity = new StringEntity(JSONObject.toJSONString(list.get(0)), "UTF-8");
                //entity.setContentEncoding("UTF-8");
                entity.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                post.setEntity(entity);
                CloseableHttpResponse httpResponse = httpClient.execute(post);
                if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    String result = EntityUtils.toString(httpResponse.getEntity());// 返回json格式;
                    JSONObject object = JSONObject.parseObject(result);
                    boolean success = object.getBooleanValue("success");
                    String message = object.getString("message");
                    //记录日志
                    new Thread(() -> {
                        WmsTmsLogWithBLOBs log = new WmsTmsLogWithBLOBs();
                        log.setParam(JSONObject.toJSONString(interfaceDTO));
                        log.setBody(result);
                        log.setUrl("WmsCQOutboundServiceImpl.updateSendOutboundDataToTMS");
                        log.setGmtCreate(new Date());
                        log.setGmtUpdate(new Date());
                        log.setSendType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                        wmsTmsLogMapper.insertSelective(log);
                    }).start();
                    if (success) {
                        Long dataId = interfaceDTO.getDataId();
                        WmsHandoverOrder handoverOrder = new WmsHandoverOrder();
                        handoverOrder.setDataId(dataId);
                        handoverOrder.setSendStatusTms(HandoverSendStatusEnum.SEND_SUCCESS.getStatusCode());
                        handoverOrder.setGmtUpdate(new Date());
                        handoverOrder.setResultMsgTms(message);
                        handoverOrderMapper.updateByPrimaryKeySelective(handoverOrder);
                        WmsHandoverOrderExcpExample excpExample = new WmsHandoverOrderExcpExample();
                        excpExample.createCriteria().andDataIdEqualTo(dataId);
                        List<WmsHandoverOrderExcp> orderExcps = handoverOrderExcpMapper.selectByExample(excpExample);
                        if (CollectionUtils.isNotEmpty(orderExcps)) {
                            //最后异常的执行数据为成功
                            WmsHandoverOrderExcp orderExcp = orderExcps.get(0);
                            orderExcp.setResultMsgTms(message);
                            orderExcp.setSendStatusTms(SendStatusEnum.SEND_SUCCESS.getValue());
                            orderExcp.setGmtUpdate(new Date());
                            if (orderExcp.getSendCountTms() < TOTAL_COUNT) {
                                orderExcp.setSendCountTms(orderExcp.getSendCountTms() + 1);
                            }
                            orderExcp.setFinalSendStatusTms(SendStatusEnum.SEND_SUCCESS.getValue());
                            handoverOrderExcpMapper.updateByPrimaryKeySelective(orderExcp);
                        }
                    } else {
                        Long dataId = interfaceDTO.getDataId();
                        WmsHandoverOrder handoverOrder = new WmsHandoverOrder();
                        handoverOrder.setDataId(dataId);
                        handoverOrder.setSendStatusTms(HandoverSendStatusEnum.SEND_FAIL.getStatusCode());
                        handoverOrder.setGmtUpdate(new Date());
                        handoverOrder.setResultMsgTms(message);
                        handoverOrderMapper.updateByPrimaryKeySelective(handoverOrder);
                        WmsHandoverOrderExcpExample excpExample = new WmsHandoverOrderExcpExample();
                        excpExample.createCriteria().andDataIdEqualTo(dataId);
                        List<WmsHandoverOrderExcp> orderExcps = handoverOrderExcpMapper.selectByExample(excpExample);
                        if (CollectionUtils.isEmpty(orderExcps)) {
                            //往接口异常表里写入数据,
                            WmsHandoverOrderExcp orderExcp = new WmsHandoverOrderExcp();
                            WmsHandoverOrder order = handoverOrderMapper.selectByPrimaryKey(dataId);
                            BeanUtils.copyProperties(order, orderExcp);
                            orderExcp.setSendStatusTms(SendStatusEnum.SEND_FAILED.getValue());
                            orderExcp.setSendCountDcs(1);
                            orderExcp.setSendCountTms(1);
                            orderExcp.setSendCountCrm(1);
                            orderExcp.setSendCountSap(1);
                            orderExcp.setDataId(dataId);
                            orderExcp.setResultMsgTms(message);
                            handoverOrderExcpMapper.insertSelective(orderExcp);
                        } else {
                            //增加调用次数
                            WmsHandoverOrderExcp orderExcp = orderExcps.get(0);
                            if (orderExcp.getSendCountTms() <= TOTAL_COUNT) {
                                orderExcp.setSendStatusTms(SendStatusEnum.SEND_FAILED.getValue());
                                orderExcp.setGmtUpdate(new Date());
                                if (orderExcp.getSendCountTms() == TOTAL_COUNT) {
                                    orderExcp.setFinalSendStatusTms(SendStatusEnum.SEND_FAILED.getValue());
                                } else {
                                    orderExcp.setSendCountTms(orderExcp.getSendCountTms() + 1);
                                }
                                orderExcp.setResultMsgTms(message);
                                handoverOrderExcpMapper.updateByPrimaryKeySelective(orderExcp);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("WmsCQOutboundServiceImpl.updateSendOutboundDataToTMS error:{}", e);
            }
        }
    }


    /**
     * 调用接口失败记录
     *
     * @param result 调用tms接口的返回结果
     * @param shipno 调度指令号
     */
    private void insertFailedData(String vehicle, String result, String shipno) {
        Runnable runnable = () -> {
            //去除重复
            HashMap<String, Object> paramMap = Maps.newHashMap();
            paramMap.put("vehicle", vehicle);
            paramMap.put("inOut", WmsGateControllerTypeEnum.GATE_OUT.getCode());
            paramMap.put("notOpen", WmsDepartureOpenStatusEnum.NOT_OPEN.getValue());
            paramMap.put("result", WmsDepartureTypeEnum.TMS_FAILED.getValue());
            paramMap.put("shipNo", shipno);
            List<WmsDepartureRegister> list = wmsDepartureRegisterExtMapper.selectTodayData(paramMap);
            if (CollectionUtils.isEmpty(list)) {
                WmsCqinboundTms tms = new WmsCqinboundTms();
                //构建数据,插入数据到本地接口表
                tms.setAtSendBusinessFlag(String.valueOf(SendBusinessFlagEnum.SEND_N.getValue()));
                tms.setAtSysSource(WmsSysSourceEnum.WMS_CREATE.getValue());
                tms.setWhCode(WhCodeEnum.UNLCN_XN_CQ.getValue());
                tms.setWhName(WhCodeEnum.UNLCN_XN_CQ.getText());
                tms.setIsDelete(DeleteFlagEnum.NORMAL.getValue());
                tms.setCreateUserName(null);
                tms.setModifyUserName(null);
                tms.setGmtCreate(new Date());
                tms.setGmtUpdate(new Date());
                tms.setWmsInOutStatus(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                tms.setTmsInnvocationCount(1);
                tms.setTmsResult(String.valueOf(Boolean.FALSE));
                tms.setSupplierVehiclePlate(vehicle);
                tms.setDispatchNo(shipno);      //出库类型保存失败数据的指令号
                wmsCqinboundTmsMapper.insertSelective(tms);
                //插入到闸门记录表
                WmsDepartureRegister departureRegister = insertWmsDepartureRegister(vehicle, shipno);
                departureRegister.setWhCode(WhCodeEnum.UNLCN_XN_CQ.getValue());
                wmsDepartureRegisterMapper.insertSelective(departureRegister);
            }
            //插入日志
            insertTmsLogAndTime(vehicle, result);
        };
        new Thread(runnable).start();
    }

    /**
     * 插入数据到出入场登记表
     *
     * @param shipno 指令号
     */
    private WmsDepartureRegister insertWmsDepartureRegister(String vehicle, String shipno) {
        WmsDepartureRegister gate = new WmsDepartureRegister();
        gate.setGmtUpdate(new Date());
        gate.setGmtCreate(new Date());
        gate.setDrVehiclePlate(vehicle);
        gate.setInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
        gate.setDrDepartureType(WmsDepartureTypeEnum.TMS_FAILED.getValue());
        gate.setDrOpenStatus(WmsDepartureOpenStatusEnum.NOT_OPEN.getValue());
        gate.setDispatchNo(shipno);
        return gate;
    }

    /**
     * 查询最后一条调用tms的闸门记录
     *
     * @param vehicle 车牌号
     * @return 返回值
     */
    private List<WmsCqinboundTms> getLastWmsCqOutboundTms(String vehicle) {
        WmsCqinboundTmsExample tmsExample = new WmsCqinboundTmsExample();
        tmsExample.setOrderByClause("id desc");
        tmsExample.setLimitStart(0);
        tmsExample.setLimitEnd(1);
        tmsExample.createCriteria().andIsDeleteEqualTo(DeleteFlagEnum.NORMAL.getValue())
                .andWmsInOutStatusEqualTo(WmsGateControllerTypeEnum.GATE_OUT.getCode())
                .andSupplierVehiclePlateEqualTo(vehicle)
                .andAtSysSourceEqualTo(WmsSysSourceEnum.WMS_CREATE.getValue());
        return wmsCqinboundTmsMapper.selectByExample(tmsExample);
    }

    private final int CALL_TMS_COUNT = 5;

    /**
     * 再计划的调用tms接口
     *
     * @param vehicle 车牌号
     * @param sysUser 用户
     */
    private void updateScheduleCallTms(String vehicle, SysUser sysUser, String shipno) {
        ScheduledExecutorService scheduledExecutorService = null;
        try {
            scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
            //开启定时线程调用tms
            ScheduledExecutorService finalScheduledExecutorService = scheduledExecutorService;
            scheduledExecutorService.scheduleAtFixedRate(() -> {
                List<WmsCqinboundTms> lastWmsCqinboundTms = getLastWmsCqOutboundTms(vehicle);
                if (CollectionUtils.isNotEmpty(lastWmsCqinboundTms)) {
                    WmsCqinboundTms tms = lastWmsCqinboundTms.get(0);
                    if (!Objects.equals(tms, null) && tms.getTmsInnvocationCount() < CALL_TMS_COUNT) {
                        tms.setId(null);
                        tms.setGmtUpdate(new Date());
                        tms.setGmtCreate(new Date());
                        tms.setCreateUserName(sysUser.getName());
                        tms.setModifyUserName(sysUser.getName());
                        tms.setTmsInnvocationCount(tms.getTmsInnvocationCount() + 1);
                        String result = null;
                        try {
                            result = callTms(WhCodeEnum.UNLCN_XN_CQ.getText(), vehicle, shipno);
                        } catch (Exception e) {
                            logger.error("WmsCQOutboundServiceImple.updateScheduleCallTms error:", e);
                            result = "{\n" +
                                    "    \"success\": false,\n" +
                                    "    \"records\": null,\n" +
                                    "    \"message\": \"调用tms接口超时失败!\"\n" +
                                    "}";
                        }
                        if (StringUtils.isNotBlank(result)) {
                            JSONObject jsonObject = JSONObject.parseObject(result);
                            String msg = jsonObject.getString("message");
                            String records = jsonObject.getString("records");
                            Boolean success = jsonObject.getBoolean("success");
                            if (success) {
                                //更新数据为成功
                                tms.setTmsResult(String.valueOf(Boolean.TRUE));
                                insertWmsCqInboundTms(sysUser.getName(), WmsSysSourceEnum.WMS_CREATE.getValue(), shipno);

                            } else {
                                logger.error("WmsCQOutboundServiceImple.updateScheduleCallTms error", msg);
                                //再调用tms 4次
                                result = "{\n" +
                                        "    \"success\": false,\n" +
                                        "    \"records\": null,\n" +
                                        "    \"message\": \"" + msg + "!\"\n" +
                                        "}";
                                tms.setTmsResult(String.valueOf(Boolean.FALSE));
                            }
                        }
                        wmsCqinboundTmsMapper.insertSelective(tms);
                        //保存对应的日志表
                        insertTmsLogAndTime(vehicle, result);
                    } else if (!Objects.equals(tms, null) && tms.getTmsInnvocationCount() >= CALL_TMS_COUNT) {
                        finalScheduledExecutorService.shutdown();
                    }
                }
            }, 0, 2, TimeUnit.MINUTES);
        } catch (Exception e) {
            logger.error("WmsCQOutboundServiceImple.updateScheduleCallTms 执行失败 error:", e);
            if (scheduledExecutorService != null) {
                scheduledExecutorService.shutdownNow();
            }
        }
    }


    /**
     * 保存调用tms入库道闸的业务表
     *
     * @param username  用户名
     * @param sysSource 数据来源--tms调用成功的数据  或者手动开闸后再调用tms成功的数据
     * @param shipno    出库调用tms接口的指令号
     */
    private void insertWmsCqInboundTms(String username, String sysSource, String shipno) {
        WmsCqinboundTms tms = new WmsCqinboundTms();
        //构建数据,插入数据到本地接口表
        tms.setAtSendBusinessFlag(String.valueOf(SendBusinessFlagEnum.SEND_N.getValue()));
        tms.setAtSysSource(sysSource);
        tms.setCreateUserName(username);
        tms.setWhCode(WhCodeEnum.UNLCN_XN_CQ.getValue());
        tms.setWhName(WhCodeEnum.UNLCN_XN_CQ.getText());
        tms.setIsDelete(DeleteFlagEnum.NORMAL.getValue());
        tms.setDispatchNo(shipno);
        tms.setCreateUserName(username);
        tms.setModifyUserName(username);
        tms.setGmtCreate(new Date());
        tms.setGmtUpdate(new Date());
        tms.setWmsOutTime(new Date());
        tms.setWmsInOutStatus(WmsGateControllerTypeEnum.GATE_OUT.getCode());
        tms.setTmsInnvocationCount(1);
        tms.setTmsResult(String.valueOf(Boolean.TRUE));
        wmsCqinboundTmsMapper.insertSelective(tms);
    }

    /**
     * 保存tms的日志和时间
     *
     * @param vehicle 用户名
     * @param result  tms的返回结果
     */

    private void insertTmsLogAndTime(String vehicle, String result) {
        //记录tms接口结果到wms_cqinbound_tms_log 表中
        Runnable runnable = () -> {
            if (StringUtils.isNotBlank(result)) {
                SimpleDateFormat milSdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
                JSONObject jsonObject = JSONObject.parseObject(result);
                String msg = jsonObject.getString("message");
                String records = jsonObject.getString("records");
                Boolean success = jsonObject.getBoolean("success");
                WmsCqinboundTmsLog log = new WmsCqinboundTmsLog();
                log.setCreateTime(new Date());
                log.setTmsInOutType(WmsGateControllerTypeEnum.GATE_OUT.getCode());
                log.setTmsInvocationTimestamp(Long.valueOf(milSdf.format(new Date())));
                log.setTmsMsg(msg);
                log.setTmsParam(vehicle);
                log.setTmsResult(String.valueOf(success));
                log.setTmsRecords(records);
                log.setTmsUrl(propertyUrl + "/mShipOut.jspx");
                wmsCqinboundTmsLogMapper.insertSelective(log);
            }
        };
        new Thread(runnable).start();
    }


    /**
     * 调用 tms 的接口(抓取验车单信息,或者生成验车合格的状态)
     */
    private String callTms(String warehouse, String vehicle, String shipno) {
        // 构建URL
        String url = propertyUrl;
        Integer time = Integer.parseInt(propertyTime);
        String encode_key = propertyKey;
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("encode-key", encode_key);
        url = url + "/mShipOut.jspx";
        map.put("warehouse", warehouse);
        map.put("vehicle", vehicle);
        map.put("shipno", shipno);
        String result = null;
        try {
            result = HttpRequestUtil.sendHttpPost(url, headerMap, map, time);
        } catch (Exception e) {
            throw new BusinessException("访问tms接口失败");
        }
        return result;
    }


}
